package me.pinion.model;

import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;
import me.pinion.kit.CommonKit;
import me.pinion.kit.PropKit;
import me.pinion.model.annotation.TableBind;
import me.pinion.model.book.Book;
import me.pinion.model.book.Chapter;
import me.pinion.model.message.Message;
import me.pinion.service.MessageService;

import java.util.HashMap;
import java.util.List;
import java.util.Map;


@TableBind(table = "user")
public class User extends XModel<User>{
    public static User dao = new User();


    MessageService messageService;


    private static Map<Object, User> USER_CACHE = new HashMap<Object, User>();

    private UserInfo userInfo;
    private List<Role> roles;

    public String getUsername(){ return this.getStr("username"); }
    public String getNickname(){ return this.getUserInfo().getStr("nickname"); }
    public String getNumber(){ return this.getStr("number")==null?"":this.getStr("number"); }

    public String getEmail(){
        return this.getStr("email")==null?"":this.getStr("email");
    }

    public User findById(Object id){
        User user = USER_CACHE.get(String.valueOf(id));
        if (user==null){
            user = super.findById(id);
            if (user != null){
                USER_CACHE.put(String.valueOf(id), user);
            }
        }
        return user;
    }

    public Map<Object, User> put(User user){
        USER_CACHE.put(String.valueOf(user.getId()), user);
        return USER_CACHE;
    }

    public UserInfo getUserInfo(){ return UserInfo.dao.findByUser(this); }

    public Map getAttributes(){return this.getAttrs(); }

    public User findByEmail(String email){ return dao.findFirst("SELECT * FROM user WHERE email=?", email); }
    public User findByNumber(String number){ return dao.findFirst("SELECT * FROM user WHERE number=?", number);}
    public User findByUsername(String number){ return dao.findFirst("SELECT * FROM user WHERE username=?", number); }

    public String getAvatar(){
        if (getStr("avatar") != null){
            return getStr("avatar");
        }else{
            String avatar = "/asset/images/default_avatar_" + (int)(Math.random() * 7) + ".png";
            this.set("avatar", avatar);
            this.update();
            return avatar;
        }
    }


    public User setPassword(String password){
        this.set("password", CommonKit.encrypt(password));
        return this;
    }

    public List<Attach> getObjects(){
        return Attach.dao.find("SELECT a.*, p.id as 'post_id' FROM attach as a, post as p WHERE p.attach_id=a.id AND p.author_id=? ORDER BY a.id DESC", this.getLong("id"));
    }

    public List<me.pinion.model.Role> getRoles(){
        if (roles==null){
            roles = me.pinion.model.Role.dao.find(PropKit.get("sql", "user.getRoles"), this.getLong("id"));
        }
        return roles;
    }
    public boolean hasRoles(String[] roles){
        if (getId() < 1){
            return false;
        }
        return this.getRoles().containsAll(me.pinion.model.Role.dao.inAuthorities(roles));
    }
    public boolean hasRole(String role){
        if (getId() < 1) return false;
        return this.getRoles().contains(Role.dao.byAuthority(role));
    }
    public boolean addRole(String role){return this.addRole(Role.dao.byAuthority(role));}
    public boolean addRole(Role role){
        Record record = new Record();
        record.set("role_id", role.get("id"));
        record.set("user_id", this.get("id"));
        Db.save("user_role", record);
        return true;
    }

    public <T extends XModel<T>> List<T> visitRank(Class<T> clazz){return Visit.dao.visitRank(clazz, this, 5); }
    public <T extends XModel<T>> List<T> visitRank(Class<T> clazz, int max){return Visit.dao.visitRank(clazz, this, max);}
    public List<Book> visitBookRank(){
        return this.visitRank(Book.class);
    }
    public List<Comment> getRecentComments(int offset, int max){
        return Comment.dao.paginate(offset, max, "SELECT \n" +
                "    c . *\n",
                "FROM\n" +
                "    comment AS c,\n" +
                "    user AS u\n" +
                "WHERE\n" +
                "    c.author_id = u.id AND u.id = ?\n" +
                "ORDER BY c.datetime DESC", this.getId()).getList();
    }


    public List<Comment> getRecentBookComments(int offset, int max){
        return Comment.dao.paginate(offset, max, "SELECT \n" +
                "    c . *\n",
                "FROM\n" +
                        "    comment AS c,\n" +
                        "    user AS u\n" +
                        "WHERE\n" +
                        "    c.author_id = u.id AND u.id = ?\n" +
                        "   AND (c.target_type=? OR c.target_type=?)" +
                        "ORDER BY c.datetime DESC", this.getId()
                , ModelType.dao.getByClass(Book.class).getId()
                , ModelType.dao.getByClass(Chapter.class).getId()).getList();
    }
    public List<Comment> getRecentBookComments(){return this.getRecentBookComments(1, 5);}


    public List<Tag> getSubscribedTags(){return  this.getSubscribedTags(1, 3); }
    public List<Tag> getSubscribedTags(int offset, int max){ return Subscription.dao.byUserAndClass(this, Tag.class,offset ,max);}




    public List<Book> getLikeBooks(){ return Like.dao.hasLike(Book.class, this); }
    public List<Book> getFavoBooks(){ return Favorite.dao.hasFavo(Book.class, this); }
    public List<Book> getOwnBooks(){ return Book.dao.listByOwner(this); }

    public int getMessageCount(){
        return messageService.count(this);
    }

    public List<Message> getUnreadMessages(){ return messageService.listByReciver(this); }


    public boolean isUser(){ return this.getId() > 0; }
    public boolean isUser(User user){ return (null == user) ? null : user.isUser(); }
}
